package com.linhngua.code.processing.graph;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.linhngua.code.processing.graph.Constants.*;
public class FunctionProcessorImpl implements FunctionProcessor {

	private float increment;

	private Function function;
	
	private float minX;
	
	private float maxX;
	
	private float minY;
	
	private float maxY;
	
	private float scaleX;
	
	private float scaleY;

	public FunctionProcessorImpl(float increment,
			Function function,float scaleX,float scaleY) {
		super();
		this.increment = increment;
		this.function = function;
		minX=-WINDOW_WIDTH/2;
		minY=-WINDOW_HEIGHT/2;
		maxX=-minX;
		maxY=-minY;
		this.scaleX=scaleX;
		this.scaleY=scaleY;
	}

	@Override
	public MathPoint[] getGraph() {

		List<MathPoint> points=new ArrayList<MathPoint>();
		
		for (float x=minX; x<maxX; x+=increment) {
			float sx=scaleX*x;
			float y=function.nextY(sx);
			MathPoint mathPoint = new MathPoint(sx, y);
			if(y!=Float.NaN&&isWithinBound(mathPoint)){
				points.add(mathPoint);
			}
			x += increment;

		}
		
		//last point
		float sx=maxX*scaleX;
		MathPoint mathPoint = new MathPoint(sx, function.nextY(sx));
		if(isWithinBound(mathPoint)){
			points.add(mathPoint);
		}
		return points.toArray(new MathPoint[0]);
	}
	
	boolean isWithinBound(MathPoint graphPoint){
		return graphPoint.x>=minX&&graphPoint.x<=maxX&&graphPoint.y>=minY&&graphPoint.y<=maxY;
	}

	@Override
	public float maxYValue() {
		MathPoint[] points=getGraph();
		if(points.length==0){
			return 0;
		}
		float y=points[0].y;
		for(int i=1;i<points.length;i++){
			if(y<points[i].y){
				y=points[i].y;
			}
		}
		return y;
	}

	@Override
	public float minYValue() {
		MathPoint[] points=getGraph();
		if(points.length==0){
			return 0;
		}
		float y=points[0].y;
		for(int i=1;i<points.length;i++){
			if(y>points[i].y){
				y=points[i].y;
			}
		}
		return y;
	}
	

	@Override
	public float scaleY() {
		float scale=1;

		float dis=disY();
		if(dis!=0){
			scale=WINDOW_HEIGHT/dis;
		}
		
		return Math.abs(scale)*scaleY;
	}

	@Override
	public float disY() {
		float y1=maxYValue();
		float y2=minYValue();
		float dis=y1-y2;
		return dis;
	}

	@Override
	public float scaleX() {
		return scaleX;
	}
	
	

}
